#include "skview.h"

#include <QDebug>
#include <QGraphicsScene>
#include <QWheelEvent>
#include <QGraphicsLineItem>
#include <QGraphicsWidget>
#include <QLabel>
#include <QGraphicsProxyWidget>
#include <QAction>
#include <QInputDialog>
#include <math.h>
#include <map>
#include "../mainwindow.h"
#include "skpoint.h"
#include "skcircle.h"
#include "skline.h"
#include "sksegment.h"

SkView::SkView(QWidget * parent):QGraphicsView(parent) //const int& width, const int& height,
{

    scene = new SkScene(this);
    sketchModel = new SketchModelWrapper();
	scene->setSketchModel(sketchModel);

    constraintState =EMPTY;

    connect(scene,SIGNAL(pointPosHasChanged(int,QPointF)),this,SLOT(pointPosChanged(int,QPointF)));
    connect(scene,SIGNAL(pointHasClicked(int)),this,SLOT(pointClicked(int)));

    connect(sketchModel,SIGNAL(viewChanged()),this,SLOT(viewChanged()));
    connect(sketchModel,SIGNAL(tablePrimitiveChanged()),this,SLOT(tablePrimitiveChanged()));
    connect(sketchModel,SIGNAL(tableConstraintChanged()),this,SLOT(tableConstraintChanged()));
    connect(sketchModel,SIGNAL(tableParameterChanged()),this,SLOT(tableParameterChanged()));
    connect(sketchModel,SIGNAL(modelSolved()),this,SLOT(viewChanged()));

    scene->setItemIndexMethod(QGraphicsScene::NoIndex);
    setSizePolicy(parent->sizePolicy());

    setScene(scene);
    setCacheMode(QGraphicsView::CacheBackground);
    setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
    setRenderHint(QPainter::Antialiasing);
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    setResizeAnchor(QGraphicsView::AnchorViewCenter);
    scale(1,-1);


}
SkScene* SkView::getSkScene(){
    return scene;
}

void SkView::setContainers(QLineEdit* k,QLineEdit* l,QLineEdit* m,QLineEdit* n){
	this->k=k;
	this->l=l;
	this->m=m;
	this->n=n;
}
void SkView::setTables(QTableView* tableConstraint,QTableView* tablePrimitive,QTableView* tableParemeter){
	this->tableConstraint = tableConstraint;
	this->tablePrimitive = tablePrimitive;
	this->tableParemeter =tableParemeter;
	this->tableConstraint->setModel(new SkModelConstraint(sketchModel,this));
	this->tablePrimitive->setModel(new SkModelPrimitive(sketchModel,this));
	this->tableParemeter->setModel(new SkModelParameter(sketchModel,this->tablePrimitive));

}

void SkView::setConsole(QPlainTextEdit* console){
	this-> console = console;
}
void SkView::setClearButton(QPushButton *pushButtonClear){
	this->clearButton = pushButtonClear;
}
void SkView::deletePrimitive(){

	QModelIndexList l = tablePrimitive->selectionModel()->selectedIndexes();
	bool ok;
	int id = l.at(0).data(Qt::DisplayRole).toInt(&ok);
	if(ok){
		sketchModel->removePrimitive(id);
	}
}

void SkView::deleteConstraint(){

	QModelIndexList l = tableConstraint->selectionModel()->selectedIndexes();
	bool ok;
	int id = l.at(0).data(Qt::DisplayRole).toInt(&ok);
	if(ok){
		sketchModel->removeConstraint(id);
	}

}
void SkView::addConstraint(){

	QAction* k = (QAction*)sender();
	clearButton->click();

	int ki = (int)EMPTY + 1;
	for(int i=0;i<ki;i++){
		if(k->text() == QString(GeometricConstraintTypeNames[i])){
			constraintState =(GeometricConstraintType)i;
			break;
		}
	}
}
void SkView::resetTables(){

}
void SkView::populateScene(){
	getSkScene()->clearScene();
	QGraphicsWidget* par = getSkScene()->getSkParent(); ///parent
	// teraz populate scene
	std::map<int,std::string> prims = sketchModel->getPrimitiveData();

	for(std::map<int,std::string>::iterator it= prims.begin(); it!=prims.end(); it++){

		std::map<int,Coordinate> pnt = sketchModel->getPrimitivePoints(it->first);

		QList<SkPoint*> skpnt;
		for(std::map<int,Coordinate>::iterator itp=pnt.begin(); itp!= pnt.end(); itp++){

			skpnt.append(new SkPoint(itp->first,QPointF(itp->second.x,itp->second.y),6,par));
		}

		if(QString(it->second.c_str())=="LINE"){
			SkPoint * p1 = skpnt.at(0);
			SkPoint * p2 = skpnt.at(1);
			new SkLine(it->first,p1,p2,par);
		}
		if(QString(it->second.c_str())=="CIRCLE"){
			SkPoint * p1 = skpnt.at(0);
			SkPoint * p2 = skpnt.at(1);
			new SkCircle(it->first,p1,p2,par);
		}
		if(QString(it->second.c_str())=="SEGMENT"){
			new SkSegment(it->first,skpnt,par);
		}
	}

}

int SkView::getPointK(){
	bool ok = false;
	int out = k->text().toInt(&ok);
	if(ok){
		return out;
	}else {
		return -1;
	}
}

int SkView::getPointL(){
	bool ok = false;
	int out = l->text().toInt(&ok);
	if(ok){
		return out;
	}else {
		return -1;
	}
}

int SkView::getPointM(){
	bool ok = false;
	int out = m->text().toInt(&ok);
	if(ok){
		return out;
	}else {
		return -1;
	}
}

int SkView::getPointN(){
	bool ok = false;
	int out = n->text().toInt(&ok);
	if(ok){
		return out;
	}else {
		return -1;
	}
}
void SkView::consoleStart(QString txt){
	console->clear();
	console->moveCursor(QTextCursor::Start);
	console->insertPlainText(txt + "\r\n");
	console->verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMaximum);

}

void SkView::consoleEnd(QString txt){
	console->clear();
	console->moveCursor(QTextCursor::End);
	console->insertPlainText(txt+ "\r\n");
}

void SkView::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_Control:
        setDragMode(dragMode()>QGraphicsView::NoDrag?QGraphicsView::NoDrag : QGraphicsView::ScrollHandDrag);
        break;
    case Qt::Key_Down:

        break;
    case Qt::Key_Left:

        break;
    default:
        QGraphicsView::keyPressEvent(event);
    }
}

void SkView::wheelEvent(QWheelEvent *event)
{
    scaleView(pow((double)2, -event->delta() / 440.0));
}

void SkView::drawBackground(QPainter *painter, const QRectF &rect)
{
    Q_UNUSED(rect);

    // Shadow
    QRectF sceneRect = this->sceneRect();

    // Fill
    QLinearGradient gradient(sceneRect.topLeft(), sceneRect.bottomRight());
    gradient.setColorAt(0, Qt::white);
    gradient.setColorAt(1, Qt::lightGray);
    painter->fillRect(rect.intersect(sceneRect), gradient);
    painter->setBrush(Qt::NoBrush);
    painter->drawRect(sceneRect);

}
void SkView::pointPosChanged(int i,QPointF newPos){

    sketchModel->pointAdjust(i,Coordinate(newPos.x(),newPos.y()));
}
void SkView::pointClicked(int i){
//    qDebug()<< "View -Clicked: " << i ;

	if(getPointK()>0){
		if(getPointL()>0){
			if(getPointM()>0){
				if(getPointN()>0){
					//CLEAR ALL K,L,M,N
					clearButton->click();
					k->setText(QString::number(i));

				}else {
					n->setText(QString::number(i));
				}
			}else {
				m->setText(QString::number(i));
			}
		}else {
			l->setText(QString::number(i));
		}
	}else {
		k->setText(QString::number(i));
	}


	switch (constraintState) {

		case CONNECT_POINTS:

			if(getPointK()>0 && getPointL()>0){

				sketchModel->addConnectPoints(getPointK(),getPointL());
				constraintState =EMPTY;
				clearButton->click();

			}
			consoleStart("CONNECT_POINTS \r\n Pleas Select 2 points");

			break;
		case FIX_POINT:
			if(getPointK()>0){
				sketchModel->addFixPoint(getPointK());
				constraintState =EMPTY;
				clearButton->click();
			}
			consoleStart("FIX_POINT \r\n Pleas Select 1 points");
			break;
		case VERTICAL:
			if(getPointK()>0 && getPointL()>0){

				sketchModel->addVertical(getPointK(),getPointL());

				constraintState =EMPTY;
				clearButton->click();
			}
			consoleStart("VERTICAL \r\n Pleas Select 2 points");
			break;
		case HORIZONTAL:
			if(getPointK()>0 && getPointL()>0){

				sketchModel->addHorizontal(getPointK(),getPointL());
				constraintState =EMPTY;
				clearButton->click();
			}
			consoleStart("HORIZONTAL \r\n Pleas Select 2 points");
			break;
		case PERPENDICULAR:
			if(getPointK()>0 && getPointL()>0 && getPointM()>0 && getPointN()>0){

				sketchModel->addPerpendicular(getPointK(),getPointL(),getPointM(),getPointN());
				constraintState =EMPTY;
				clearButton->click();
			}
			consoleStart("PERPENDICULAR \r\n Pleas Select 4 points");
			break;
		case PARALLEL:
			if(getPointK()>0 && getPointL()>0 && getPointM()>0 && getPointN()>0){

				sketchModel->addParallel(getPointK(),getPointL(),getPointM(),getPointN());
				constraintState =EMPTY;
				clearButton->click();
			}
			consoleStart("PARALLEL \r\n Pleas Select 4 points");
			break;
		case DISTANCE:
			if(getPointK()>0 && getPointL()>0 ){

				skreal paramValue =0.0;
				bool ok;
				// FIXME moze byc getDouble(
				QString text = QInputDialog::getText(this,	tr("Parameter"),tr("Enter parameter value :"),
																QLineEdit::Normal,tr("50.0"),&ok );
				if( ok && !text.isEmpty() )
				{
					bool ok2;
					paramValue = text.toDouble(&ok2);
					if(ok2){
						sketchModel->addDistance(getPointK(),getPointL(),paramValue);
					}
				}

				constraintState =EMPTY;
				clearButton->click();
			}
			consoleStart("DISTANCE \r\n Pleas Select 2 points");
			break;
			break;
		case ANGLE:
			if(getPointK()>0 && getPointL()>0 && getPointM()>0 && getPointN()>0){

				skreal paramValue =0.0;
				bool ok;
				// FIXME moze byc getDouble(
				QString text = QInputDialog::getText(this,	tr("Angle"),tr("Enter angle (degrees) value :"),
																QLineEdit::Normal,tr("50.0"),&ok );
				if( ok && !text.isEmpty() )
				{
					bool ok2;
					paramValue = text.toDouble(&ok2);
					if(ok2){
						sketchModel->addAngle(getPointK(),getPointL(),getPointM(),getPointN(),paramValue);
					}
				}

				constraintState =EMPTY;
				clearButton->click();
			}
			consoleStart("ANGLE \r\n Pleas Select 4 points");
			break;
		case TANGENCY:
			if(getPointK()>0 && getPointL()>0 && getPointM()>0 && getPointN()>0){

				sketchModel->addTangency(getPointK(),getPointL(),getPointM(),getPointN());
				constraintState =EMPTY;
				clearButton->click();
			}
			consoleStart("TANGENCY \r\n Pleas Select 4 points");
			break;
		case SAME_LENGTH:
			if(getPointK()>0 && getPointL()>0 && getPointM()>0 && getPointN()>0){

				sketchModel->addSameLength(getPointK(),getPointL(),getPointM(),getPointN());
				constraintState =EMPTY;
				clearButton->click();
			}
			consoleStart("SAME_LENGTH \r\n Pleas Select 4 points");
			break;
		default:
			break;
	}

}
void SkView::drawLine(){
	getSkScene()->drawLine();
}
void SkView::drawSegment(){
	getSkScene()->drawSegment();
}
void SkView::drawCircle(){
	getSkScene()->drawCircle();
}

void SkView::scaleView(qreal scaleFactor)
{
    qreal factor = matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
    if (factor < 0.07 || factor > 100)
        return;

    scale(scaleFactor, scaleFactor);
}
void SkView::solve(){
	sketchModel->solve();
}
void SkView::relax(){
	sketchModel->relax();
}

void SkView::viewChanged(){
	populateScene();
	std::list<std::string> msg =sketchModel->getMessages();
	QString qs;
	for(std::list<std::string>::iterator it = msg.begin(); it!= msg.end(); it++){
		qs.append(it->c_str());
	}
	consoleStart(qs);
}
void SkView::tablePrimitiveChanged(){
	((SkModelPrimitive*)tablePrimitive->model())->resetList();
}
void SkView::tableConstraintChanged(){
	((SkModelConstraint*)tableConstraint->model())->resetList();
}
void SkView::tableParameterChanged(){
	((SkModelParameter*)tableParemeter->model())->resetList();
}
SkView::~SkView(){
	delete sketchModel;
}

